local filename = "roomcmd.lua"

local skynet = require "skynet"
local cluster = require "skynet.cluster"
require "skynet.manager"

local servicepoolmng = require "incrservicepoolmng"
local configdao = require "configdao"
local timetool = require "timetool"
local filelog = require "filelog"

require "pdkenum"

local CMD = {}
local table_service_map = {}
local index_to_code = {}
local table_list = {publist = {}, mylist = {}}
local robotsnum = {pub = {}, mine = {}, match = {}, coinmatch = {}}
local router
local service = {
	code_map = {},
	idx = 1,
}
local rolestats = {}
local counter = {
	zijian_diamond = 0,
	match_diamond = 0,
	zijian_coin = 0,
	match_coin = 0,
	zijian_fangka = 0,
}

-- 生成一个桌子号，随机码
local function gen_table_code(table_index, create_rid, table_conf)
	-- 去hall节点生成code，同时 hall节点保存了code -> index 对应关系
	-- hall节点也可以是gata节点
	local newcode = cluster.call("hallnode", ".router", "create_table_code", skynet.getenv("nodename"), table_index, create_rid, table_conf)
	return newcode
end

function CMD.init_table_pool(nodeconf)
	service.idle_table_mng = servicepoolmng:new({}, {service_name = "table", service_size = nodeconf.tablesize, incr=nodeconf.tableinrc})
end

function CMD.update_table_player(idx, num, is_public, match_type, room_type)
	if is_public and is_public == 1 then
		table_list.publist[idx].cur_player = num
	else
		-- table_list.mylist[idx].cur_player = num
		if match_type then
			if room_type == ERoomType.ROOM_TYPE_DIAMOND then
				router.update_match_fulltable(idx, num, match_type)
			-- elseif room_type == ERoomType.ROOM_TYPE_COIN then
			-- 	router.update_coinmatch_fulltable(idx, num, match_type)
			end
		end
	end
end

function CMD.change_robot_num(num, idx, is_public, match_type, room_type)
	if is_public and is_public == 1 then
		robotsnum.pub[idx] = (robotsnum.pub[idx] or 0) + num
	else
		robotsnum.mine[idx] = (robotsnum.mine[idx] or 0) + num
	end
	if match_type then
		if room_type == ERoomType.ROOM_TYPE_COMMON then
			robotsnum.match[match_type] = (robotsnum.match[match_type] or 0) + num
		elseif room_type == ERoomType.ROOM_TYPE_COIN then
			robotsnum.coinmatch[match_type] = (robotsnum.coinmatch[match_type] or 0) + num
		end
	end
end

function CMD.get_gamenode_data()
	return table_service_map
end

function CMD.get_gamenode_codes()
	return index_to_code
end

function CMD.getpubtablelist(rid, roledata)
	local list = {publist = {}, mylist = {}}
	local i = 1
	for idx, data in pairs(table_list.publist) do
		list.publist[i] = {
			table_index	= data.table_index,
			table_code	= data.table_code,
			dizhu 		= data.base_score,
			ruchang		= data.enter_diamond,
			lichang		= data.leave_diamond,
			conf_intro	= data.conf_intro,
			max_player	= nil,
			cur_player	= data.cur_player,
			create_time	= data.create_time,
		}
		i = i + 1
		if i > 30 then
			break
		end
	end
	--获得匹配场信息
    list.matchlist = router.get_matchlist()
	return list
end

--[[
function CMD.getcoinmatchlist(rid, roledata)
    local list = {publist = {}, mylist = {}}
	local i = 1
	for idx, data in pairs(table_list.publist) do
		list.publist[i] = {
			table_index	= data.table_index,
			table_code	= data.table_code,
			dizhu 		= data.base_score,
			ruchang		= data.enter_diamond,
			lichang		= data.leave_diamond,
			conf_intro	= data.conf_intro,
			max_player	= nil,
			cur_player	= data.cur_player,
			create_time	= data.create_time,
		}
		i = i + 1
		if i > 30 then
			break
		end
	end
	--获得匹配场信息
    list.matchlist = router.get_coinmatchlist()
	return list
end
--]]

function CMD.getgamestate()
	local result = {
        zijian_fangka = counter.zijian_fangka,
        zijian_diamond = counter.zijian_diamond,
        zijian_coin = counter.zijian_coin,
        match_diamond = counter.match_diamond,
        match_coin = counter.match_coin,
    }
	result.match_diamond = result.match_diamond + router.get_playing_player()
	result.match_coin = result.match_coin + router.get_playing_player_coin()
	return result
end

--[[游戏房间类型
EGameRoomType = {
    ROOM_TYPE_ZIJIAN_FANGKA = 1,        --自建房卡房
    ROOM_TYPE_ZIJIAN_ZUANSI = 2,        --自建钻石房
    ROOM_TYPE_MATCH_ZUANSHI = 3,        --匹配钻石房
    ROOM_TYPE_MATCH_COIN = 4,           --匹配金豆房
    ROOM_TYPE_ZIJIAN_COIN = 5,          --自建金豆房
}
--]]
local function player_counter(gtype, num)
	if gtype == 1 then
		counter.zijian_fangka = counter.zijian_fangka + num
	elseif gtype == 2 then
		counter.zijian_diamond = counter.zijian_diamond + num
	elseif gtype == 3 then
		counter.match_diamond = counter.match_diamond + num
	elseif gtype == 4 then
		counter.match_coin = counter.match_coin + num
	elseif gtype == 5 then
		counter.zijian_coin = counter.zijian_coin + num
	end
end

function CMD.createtable(rid, rdata, args)
	-- filelog.sys_error("createtable ======>>>", args)
	local responsemsg = {}
	if router.will_kill then
		responsemsg.retcode = EErrCode.ERR_INVALID_REQUEST
		responsemsg.retstr = "服务器维护中"
		return responsemsg
	end
	if rolestats[rid] then
		filelog.sys_error("CMD.createfriendtable creating!")
		return
	end
	rolestats[rid] = 1
	local role_data = router.get_role_data(rid)
	if role_data then
		rolestats[rid] = nil
		return
	end
	local card_cost_type = 1
	local card_cost = 4
	args.config.retain_to_num = args.config.retain_to_num or 8
	if args.config.retain_to_num == 4 then
		card_cost = 2
	end
	args.config.table_type = args.config.table_type or ERoomType.ROOM_TYPE_COMMON
	local money = rdata.money
	if args.config.table_type == ERoomType.ROOM_TYPE_FRIEND then
		if card_cost_type == 1 then
			-- if rdata.money.fangka < card_cost then
			if rdata.money.coin < card_cost*100 then
				responsemsg.retcode = EErrCode.ERR_NOTENOUGH_COIN
				responsemsg.retstr = "金币数量不够！"
				filelog.sys_error("CMD.createfriendtable lack of fangka 1")
				rolestats[rid] = nil
				return responsemsg
			end
		else
			-- if rdata.money.fangka < card_cost/3 then
			if rdata.money.fangka < 100*card_cost/3 then
				responsemsg.retcode = EErrCode.ERR_NOTENOUGH_COIN
				responsemsg.retstr = "金币数量不够！"
				filelog.sys_error("CMD.createfriendtable lack of fangka 2")
				rolestats[rid] = nil
				return responsemsg
			end
		end
	elseif args.config.table_type == ERoomType.ROOM_TYPE_COMMON then
		if not money or not money.diamond then
			responsemsg.retcode = EErrCode.ERR_NOT_ENOUGH_DIAMOND
			responsemsg.retstr = "您的金豆不足，请前往充值！"
			filelog.sys_error("CMD.createfriendtable lack of diamond 1")
			rolestats[rid] = nil
			return responsemsg
		end
	
		if money.diamond < (args.config.enter_diamond or 1000) then
			responsemsg.retcode = EErrCode.ERR_NOT_ENOUGH_DIAMOND
			responsemsg.retstr = "您的金豆不足，请前往充值！"
			filelog.sys_error("CMD.createfriendtable lack of diamond 2")
			rolestats[rid] = nil
			return responsemsg
		end
	elseif args.config.table_type == ERoomType.ROOM_TYPE_COIN then
		if not money or not money.coin then
			-- responsemsg.retcode = EErrCode.ERR_NOT_ENOUGH_COIN
			responsemsg.retcode = EErrCode.ERR_NOT_ENOUGH_DIAMOND
			responsemsg.retstr = "您的金币不足，请前往充值！"
			filelog.sys_error("CMD.createfriendtable lack of coin 1")
			rolestats[rid] = nil
			return responsemsg
		end
		if (money.coin < 10) or (money.coin + money.diamond < (args.config.enter_diamond or 1000)) then
			-- responsemsg.retcode = EErrCode.ERR_NOT_ENOUGH_COIN
			responsemsg.retcode = EErrCode.ERR_NOT_ENOUGH_DIAMOND
			responsemsg.retstr = "您的金币不足，请前往充值！"
			filelog.sys_error("CMD.createfriendtable lack of coin 2")
			rolestats[rid] = nil
			return responsemsg
		end
	end

	local conf = {
		room_type = args.config.table_type or ERoomType.ROOM_TYPE_COMMON,
		game_room_type = args.config.game_room_type or EGameRoomType.ROOM_TYPE_ZIJIAN_ZUANSI,
		name = rdata.info.rolename .. "的房间",
		game_type = args.config.mode or args.config.game_type or EGameType.GAME_TYPE_NORMAL,
		blackheart3 = args.config.blackheart3 or 2,
		max_player_num = 3,	--最大玩家数
		is_public = args.config.is_public or 1,
		min_player_num = 3,	-- 最少玩家数
	    create_user_rid = rid,
	    create_user_name = rdata.info.rolename,
	    create_user_logo = rdata.info.logo,
	    create_time = timetool.get_time(),
		action_timeout = 30,	--玩家出牌时间
		tuoguan_action_time = 2,
		base_score = args.config.base_diamond or 100,
		max_score = args.config.max_diamond	or 2000,
		min_carry_diamond = args.config.enter_diamond or 200,
		leave_carry_diamond = args.config.leave_diamond or 200,
		rid = rid,
		retain_time = rdata.table_persist or 10,	-- 桌子保留时间
    	ready_timeout = 20,	-- 准备超时时长
    	max_watch_playernum = 5,
		game_times = args.config.retain_to_num or 0,
		common_times = 1,	-- 基础倍数
		card_cost = card_cost,
		action_timeout_count = 1,
		match_type = args.config.match_type,
		delay = 60,
	}
	if conf.room_type == ERoomType.ROOM_TYPE_FRIEND then
		conf.retain_time = 10
		conf.base_score = 1
		conf.game_room_type = EGameRoomType.ROOM_TYPE_ZIJIAN_FANGKA
	elseif conf.room_type == ERoomType.ROOM_TYPE_COIN then
		if not conf.game_room_type then
			conf.game_room_type = EGameRoomType.ROOM_TYPE_ZIJIAN_COIN
		end
	end
	-- check --
	if conf.room_type < 1 or conf.room_type > 3 then
		conf.room_type = ERoomType.ROOM_TYPE_COMMON
	end
	if conf.game_type < 1 or conf.game_type > 4 then
		conf.game_type = EGameType.GAME_TYPE_NORMAL
	end

	local tableservice = service.idle_table_mng:create_service()
	local table_code, table_service, idx
	if tableservice ~= nil then
		--生成随机码
		table_service = tableservice.service
		idx = service.idx
		table_code = gen_table_code(idx, rid, args.config)

		conf.table_code = table_code
		conf.create_time = timetool.get_time()
		conf.idx = idx
		service.code_map[table_code] = true
		local result, msg = skynet.call(table_service, "lua", "start", conf)
		if not result then
			pcall(skynet.kill, table_service)
			service.code_map[table_code] = nil
			responsemsg.retcode = EErrCode.ERR_SYSTEM_ERROR
			responsemsg.retstr = "系统错误，创建朋友桌失败！"
			filelog.error("CMD.createfriendtable failed!")
			rolestats[rid] = nil
			return responsemsg
		end
		if conf.room_type == ERoomType.ROOM_TYPE_COMMON then
			if conf.is_public and conf.is_public == 1 then
				table_list.publist[idx] = {
					table_type		= conf.room_type,
					table_index		= idx,
					table_code		= table_code,
					base_score 		= conf.base_score,
					enter_diamond	= conf.min_carry_diamond,
					leave_diamond	= conf.leave_carry_diamond,
					conf_intro		= {game_type = conf.game_type, blackheart3 = conf.blackheart3},
					max_player		= conf.max_player_num,
					cur_player		= 0,
					create_time		= conf.create_time,
					game_type		= conf.game_type,
				}
			end
		end

		service.idx = service.idx + 1
	else
		filelog.sys_error("CMD:createtable roomsvr's idle_table_mng has no enough tableservice!")
		responsemsg.retcode = EErrCode.ERR_SYSTEM_ERROR
		responsemsg.retstr = "系统错误，创建房间失败！"
		rolestats[rid] = nil
		return responsemsg
	end
	--[[
	codelist[code] = {
		nodename = gamenode,
		table_index = table_index,
		create_rid = rid,
		conf = conf,
		create_time = timetool.get_time()
	}
	--]]

	responsemsg.table_index = idx
	table_service_map[table_code] = {
		table_index = idx,
		table_service = table_service,
		create_rid = rid,
		conf = conf,
		create_time = conf.create_time,
	}
	index_to_code[idx] = table_code
	rolestats[rid] = nil
    return responsemsg
end

function CMD.entertable(rid, rdata, args)
	-- filelog.debug("entertable ======>", rid, args)
	local responsemsg = {}
	if router.will_kill then
		responsemsg.retcode = EErrCode.ERR_INVALID_REQUEST
		responsemsg.retstr = "服务器维护中"
		return responsemsg
	end
	if rolestats[rid] then
		filelog.sys_error("CMD.entertable entering!")
		return
	end
	rolestats[rid] = 1
	local role_data = router.get_role_data(rid)
	if role_data then
		filelog.sys_error("CMD.entertable: 玩家进桌状态异常！")
		rolestats[rid] = nil
		return
	end
	local code = index_to_code[args.table_index]
	if not code or not table_service_map[code] then
		responsemsg.retcode = EErrCode.ERR_INVALID_PARAMS
		responsemsg.retstr = "没有找到桌子！"
		filelog.sys_error("CMD.entertable: 没有找到桌子！")
	else
		local room_type = table_service_map[code].conf.room_type
		local game_room_type = table_service_map[code].conf.game_room_type
		if room_type == ERoomType.ROOM_TYPE_COMMON then
			if router.check_is_matchtable(args.table_index) then
				responsemsg.retcode = EErrCode.ERR_INVALID_PARAMS
				responsemsg.retstr = "没有找到桌子！"
				filelog.error("CMD.entertable match: 没有找到桌子！")
				rolestats[rid] = nil
				return responsemsg
			end
		elseif room_type == ERoomType.ROOM_TYPE_COIN then
			if router.check_is_coinmatchtable(args.table_index) then
				responsemsg.retcode = EErrCode.ERR_INVALID_PARAMS
				responsemsg.retstr = "没有找到桌子！"
				filelog.error("CMD.entertable coinmatch: 没有找到桌子！")
				rolestats[rid] = nil
				return responsemsg
			end
		end
		local table_service = table_service_map[code].table_service
		local table_index = table_service_map[code].table_index
		args = args or {}
		args.rid = rid
		args.playerinfo = rdata.info
		args.money = rdata.money
		local ok, result = pcall(skynet.call, table_service, "lua", "entertable", args)
		if ok then
			responsemsg = result
			if (not result.retcode or result.retcode == 0) and rid > 100 then
				router.forward(rid, table_service, table_index)
				player_counter(game_room_type, 1)
			end
		else
			responsemsg.retcode = EErrCode.ERR_INVALID_PARAMS
			responsemsg.retstr = "没有找到桌子！"
			filelog.sys_error("CMD.entertable: 桌子已经不存在！", result)
		end
	end
	rolestats[rid] = nil
	return responsemsg
end

function CMD.entertraintable(rid, rdata, args)
	local responsemsg = {}
	if router.will_kill then
		responsemsg.retcode = EErrCode.ERR_INVALID_REQUEST
		responsemsg.retstr = "服务器维护中"
		return responsemsg
	end
	args.config = args.config or {}
	args.config.is_public = 0
	args.config.table_type = ERoomType.ROOM_TYPE_SYSTEM
	local resp = CMD.createtable(rid, rdata, args)
	if resp and resp.table_index then
		local idx = resp.table_index
		local code = index_to_code[idx]
		local num = table_service_map[code].conf.max_player_num
		skynet.fork(function()
			local _rdata = {}
			local _rid = 0	-- 机器人rid从 1 ~ 100
			for i = 1, num - 1 do
				skynet.sleep(100)
				
				_rid = _rid + 1
				_rdata.money = {diamond = 1000000}
				_rdata.info = {
					rolename = "陪练" .. _rid,
					logo = "2",
					sex = 0,
				}
				CMD.entertable(_rid, _rdata, {table_index = idx})
			end
		end)
		return resp
	end
	return resp
end

function CMD.reentertable(rid, rdata, args)
	local responsemsg = {}
	local role_data = router.get_role_data(rid)
	if not role_data or not role_data.tablesvr then
		responsemsg.retcode = EErrCode.ERR_INVALID_REQUEST
		responsemsg.retstr = "没有找到桌子！"
		filelog.sys_error("CMD.reentertable: 没有找到桌子！")
		router.unforward(rid, args.table_index)
	else
		local table_service = role_data.tablesvr
		args = args or {}
		args.rid = rid
		args.playerinfo = rdata.info
		args.money = rdata.money
		local ok, result = pcall(skynet.call, table_service, "lua", "reentertable", args)
		if not ok then
			responsemsg.retcode = EErrCode.ERR_INVALID_REQUEST
			responsemsg.retstr = "没有找到桌子！"
			filelog.sys_error("CMD.reentertable: 没有找到桌子！", result)
		else
			responsemsg = result
		end
		if responsemsg then
			if responsemsg.retcode and responsemsg.retcode ~= 0 then
				router.unforward(rid, args.table_index)
			else
				router.forward(rid, table_service, role_data.idx)
			end
		end
	end
	return responsemsg
end

function CMD.rid_change_diamond(rid, begindiamond, value, enddiamond)
	local role_data = router.get_role_data(rid)
	if not role_data or not role_data.tablesvr then
		filelog.sys_error("CMD.rid_change_diamond: 玩家没在游戏中！")
		return
	else
		local table_service = role_data.tablesvr
		skynet.send(table_service, "lua", "rid_change_diamond", rid, begindiamond, value, enddiamond)
	end
end

function CMD.get_tableinfo(table_index, rid)
	local roledata = router.get_role_data(rid)
	if not roledata then return end
	local table_code = index_to_code[table_index]
	if not table_code then return end
	return table_service_map[table_code]
end

function CMD.get_alltableinfo()
	local responsemsg = {
		pub_tableinfos = {},
		match_infos = {},
		coin_match_infos = {},
		all_pubnum = 0,
		all_minenum = 0,
		all_pubrobots = 0,
		all_minerobots = 0,
		-- all_diamondnum = 0,
		-- all_coinnum = 0,
		-- all_diamondrobots = 0,
		-- all_coinrobots = 0,
		table_num = 0,
	}
	
	for _, data in pairs(table_list.publist) do
		responsemsg.table_num = responsemsg.table_num + 1
		responsemsg.pub_tableinfos[data.table_index] = {
			table_index 	= data.table_index,
			base_score 		= data.base_score,
			enter_diamond	= data.enter_diamond,
			leave_diamond	= data.leave_diamond,
			max_player		= data.max_player,
			cur_player		= data.cur_player,
			match_type		= data.match_type,
			table_type		= data.table_type,
			robot_num		= robotsnum.pub[data.table_index] or 0,
			game_type		= data.game_type,
		}
		responsemsg.all_pubnum = responsemsg.all_pubnum + (data.cur_player or 0)
		responsemsg.all_pubrobots = responsemsg.all_pubrobots + (robotsnum.pub[data.table_index] or 0)
	end
	-- for _, data in pairs(table_list.mylist) do
	-- 	responsemsg.pub_tableinfos[data.table_index] = {
	-- 		table_index 	= data.table_index,
	-- 		base_score 		= data.base_score,
	-- 		enter_diamond	= data.enter_diamond,
	-- 		leave_diamond	= data.leave_diamond,
	-- 		max_player		= data.max_player,
	-- 		cur_player		= data.cur_player,
	-- 		match_type		= data.match_type,
	-- 		table_type		= data.table_type,
	-- 		robot_num		= robotsnum.mine[data.table_index],
	-- 	}
	-- responsemsg.all_minenum = responsemsg.all_minenum + (data.cur_player or 0)
	-- responsemsg.all_minerobots = responsemsg.all_minerobots + (robotsnum.mine[data.table_index] or 0)
	-- end

	----[[
	local match_lists, waiting_robot, waiting_player, unfull_table_num = router.get_matchlist(true)
	for index, list in pairs(match_lists) do
		responsemsg.match_infos[index] = {
			cur_total_player = list.cur_total_player,
			cur_robot_num = robotsnum.match[index] or 0,
			enter_score = list.conf_intro.enter_diamond,
			base_score = list.conf_intro.base_diamond,
			game_type = list.conf_intro.game_type,
			waiting_player = waiting_player[index] or 0,
			waiting_robot = waiting_robot[index] or 0,
			unfull_table_num = unfull_table_num,
		}
	end
	--[[
	local coin_match_lists = router.get_coinmatchlist()
	for index, list in pairs(coin_match_lists) do
		if responsemsg.coin_match_infos[index] == nil then
			responsemsg.coin_match_infos[index] = {
				cur_total_player = list.cur_total_player,
				cur_robot_num = robotsnum.coinmatch[index] or 0,
				enter_score = list.conf_intro.enter_diamond,
				game_type = list.conf_intro.game_type
			}
		end
	end
	--]]
	return responsemsg
end

function CMD.delete(table_code)
	local idx
	if table_service_map[table_code] then
		local table_service = table_service_map[table_code].table_service
		idx = table_service_map[table_code].table_index
		table_service_map[table_code] = nil
		index_to_code[idx] = nil
		router.clear_full_matchtable(idx)
		skynet.send(table_service, "lua", "exit_service")
		cluster.send("hallnode", ".router", "del_table_code", table_code, skynet.getenv("nodename"), idx)
	end
	if idx then
		table_list.publist[idx] = nil
		table_list.mylist[idx] = nil
	end
end

function CMD.destroytable(table_code, table_index)
	if table_service_map[table_code] then
		local table_service = table_service_map[table_code].table_service
		skynet.send(table_service, "lua", "leaveallplayers")
	end
end

function CMD.playerleavetable(rid, game_room_type)
	if rid and rid > 100 then
		router.unforward(rid)
		player_counter(game_room_type, -1)
	end
end

function CMD.set_gameend_flag()
	router.will_kill = true
	for k, v in pairs(table_service_map) do
		skynet.send(v.table_service, "lua", "kill")
	end
end

function CMD.set_tableend_flag(code)
	return true
end

function CMD.clear_player_state(rid)
	router.unforward(rid)
end

function CMD.init(base)
	router = base
end

return CMD